package net.neptech.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import net.neptech.api.SystemApi;
import net.neptech.dto.workflow.UserQueryDto;
import net.neptech.model.dto.*;
import net.neptech.dto.sys.StaffDTO;
import net.neptech.enums.workflow.*;
import net.neptech.model.dto.node.Node;
import net.neptech.model.sys.Dept;
import net.neptech.model.workflow.*;
import net.neptech.service.*;
import net.neptech.util.DataUtil;
import net.neptech.util.JsonUtil;
import net.neptech.util.NodeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author Saya
 * @Date 2025/8/20 12:06
 * @Description TODO
 **/
@Service
@Slf4j
public class RemoteServiceImpl implements RemoteService {

    @Autowired
    private InstanceRecordService instanceRecordService;
    @Autowired
    private InstanceNodeRecordService instanceNodeRecordService;
    @Autowired
    private InstanceAssignUserRecordService processNodeRecordAssignUserService;
    @Autowired
    private InstanceService processInstanceService;
    @Autowired
    private InstanceCopyService processCopyService;
    @Autowired
    private InstanceUserCopyService instanceUserCopyService;
    @Autowired
    private WorkflowService processService;
    @Autowired
    private GroupService groupService;
    //    @Autowired
//    private RedisTemplate<Object, Object> redisTemplate;
    @Autowired
    private NodeDataService nodeDataService;
    @Autowired
    private MessageService messageService;
    @Autowired
    private InstanceExecutionService instanceExecutionService;
    @Autowired
    private SystemApi systemApi;

    /**
     * 根据用户id查询角色id集合
     */
    @Override
    public List<String> loadRoleIdListByUserId(String userId) {
        List<String> tmp = systemApi.getRoleIdsByUserId(userId).getData();
        List<String> res = new ArrayList<>();
        tmp.forEach(id -> res.add(String.valueOf(id)));
        return res;
    }

    /**
     * 根据部门id获取部门列表
     */
    @Override
    public List<Dept> queryDeptList(List<String> deptIdList) {
        List<String> tmp = new ArrayList<>(deptIdList);
        return systemApi.getDeptByDeptIds(tmp).getData();
    }

    /**
     * 保存待办任务
     */
    @Override
    public void saveMessage(MessageDto messageDto) {
        InstanceRecord instanceRecord = instanceRecordService.lambdaQuery().eq(InstanceRecord::getProcessInstanceId, messageDto.getProcessInstanceId()).one();
        String userId = instanceRecord.getUserId();
        StaffDTO userDto = systemApi.getStaffByUserId(userId).getData();
        if (StrUtil.equals(MessageTypeEnum.TODO_TASK.getType(), messageDto.getType())) {
            messageDto.setTitle(StrUtil.format("[{}]提交的“{}”待您处理", userDto.getStaffName(), instanceRecord.getName()));
            messageDto.setContent(StrUtil.format("[{}]提交的任务[{}]需要您来处理，请及时查看", userDto.getStaffName(), instanceRecord.getName()));
        }
        messageDto.setStartUserId(userId);
        messageDto.setStartUserName(userDto.getStaffName());
        messageDto.setFlowName(instanceRecord.getName());
        messageDto.setGroupName(instanceRecord.getGroupName());
        messageService.saveMessage(messageDto);
        //TODO这里要重新实现sendMsg方法（送往第三方api，本地直接入库，考虑交给轮询处理消息获取）
//        ApiStrategyFactory.getStrategy().sendMsg(messageDto);
    }

    /**
     * 根据角色id集合查询用户id集合
     */
    @Override
    public List<String> queryUserIdsByRoleIds(List<Long> roleIdList) {
        UserQueryDto userQueryDto = UserQueryDto.builder().roleIdList(roleIdList).build();
        return systemApi.getUserIdsByDto(userQueryDto).getData();
    }

    /**
     * 根据用户id查询上级部门列表
     */

    @Override
    public List<String> queryUserIdsByRoleIdsAndDeptIds(UserQueryDto userQueryDto) {
        return systemApi.getUserIdsByDto(userQueryDto).getData();
    }

    /**
     * 保存抄送
     */
    @Transactional
    @Override
    public void saveCC(InstanceCopyDto copyDto) {
        String processInstanceId = copyDto.getInstanceId();
        InstanceRecord instanceRecord = instanceRecordService.lambdaQuery().eq(InstanceRecord::getProcessInstanceId, processInstanceId).one();
        //批量保存抄送
        List<InstanceCopy> processInstanceCopyList = new ArrayList<>();
        for (String uid : copyDto.getUserIdList()) {
            InstanceCopy instanceCopy = BeanUtil.copyProperties(copyDto, InstanceCopy.class);
            instanceCopy.setGroupId(instanceRecord.getGroupId());
            instanceCopy.setGroupName(instanceRecord.getGroupName());
            instanceCopy.setProcessName(instanceRecord.getName());
            instanceCopy.setStartTime(instanceRecord.getCreateTime());
            instanceCopy.setUserId(uid);
            processInstanceCopyList.add(instanceCopy);
        }
        processCopyService.saveBatch(processInstanceCopyList, 50);
        //查询出当前流程实例中有过抄送的用户
        List<InstanceUserCopy> existUserCopyList = instanceUserCopyService.lambdaQuery().in(InstanceUserCopy::getUserId, copyDto.getUserIdList()).eq(InstanceUserCopy::getProcessInstanceId, copyDto.getInstanceId()).list();
        List<String> existUserIdList = existUserCopyList.stream().map(InstanceUserCopy::getUserId).toList();
        //以流程为维度 插入用户是否收到抄送了
        List<InstanceUserCopy> processInstanceUserCopyList = new ArrayList<>();
        for (String s : copyDto.getUserIdList()) {
            if (existUserIdList.contains(s)) {
                continue;
            }
            InstanceUserCopy processInstanceUserCopy = BeanUtil.copyProperties(copyDto, InstanceUserCopy.class);
            processInstanceUserCopy.setGroupId(instanceRecord.getGroupId());
            processInstanceUserCopy.setGroupName(instanceRecord.getGroupName());
            processInstanceUserCopy.setProcessName(instanceRecord.getName());
            processInstanceUserCopy.setUserId(s);
            processInstanceUserCopyList.add(processInstanceUserCopy);
        }
        if (CollUtil.isNotEmpty(processInstanceUserCopyList)) {
            instanceUserCopyService.saveBatch(processInstanceUserCopyList, 50);
        }
    }

    /**
     * 检查是否是所有的父级
     */
    @Override
    public Boolean checkIsAllParent(CheckParentDto checkParentDto) {
        Long parentId = checkParentDto.getParentId();
        List<Long> deptIdList = checkParentDto.getDeptIdList();
        //查询子级包括自己
        List<Dept> allDept = systemApi.getAllDept().getData();
        List<Dept> childrenDeptList = DataUtil.selectChildrenByDept(parentId, allDept);
        List<Long> childrenDeptIdList = childrenDeptList.stream().map(Dept::getDeptId).collect(Collectors.toList());
        childrenDeptIdList.remove(parentId);
        List<Long> remainIdList = CollUtil.removeAny(deptIdList, ArrayUtil.toArray(childrenDeptIdList, Long.class));
        return remainIdList.isEmpty();
    }

    /**
     * 根据部门id集合查询用户id集合
     */
    @Override
    public List<String> queryUserIdListByDepIdList(List<Long> deptIdList) {
        UserQueryDto userQueryDto = UserQueryDto.builder().deptIdList(deptIdList).build();
        return systemApi.getUserIdsByDto(userQueryDto).getData();
    }

    /**
     * 检查是否是所有的子级
     */
    @Override
    public Boolean checkIsAllChild(CheckChildDto checkChildDto) {
        Long childId = checkChildDto.getChildId();
        List<Long> deptIdList = checkChildDto.getDeptIdList();
        //查询父级包括自己
        List<Dept> allDept = systemApi.getAllDept().getData();
        List<Dept> parentDeptList = DataUtil.selectParentByDept(childId, allDept);
        List<Long> parentDeptIdList = parentDeptList.stream().map(Dept::getDeptId).collect(Collectors.toList());
        parentDeptIdList.remove(childId);
        List<Long> remainIdList = CollUtil.removeAny(deptIdList, ArrayUtil.toArray(parentDeptIdList, Long.class));
        return remainIdList.isEmpty();
    }

    /**
     * 获取用户的信息-包括扩展字段
     */
    @Override
    public Map<String, Object> queryUserAllInfo(String userId) {

        StaffDTO user = systemApi.getStaffByUserId(userId).getData();
        //TODO这里会出问题
        return BeanUtil.beanToMap(user, "id", "name", "deptId", "parentId");
    }

    /**
     * 查询上级部门
     */
    @Override
    public List<Dept> queryParentDeptList(Long deptId) {
        List<Dept> allDept = systemApi.getAllDept().getData();
        return DataUtil.selectParentByDept(deptId, allDept);
    }


    /**
     * 批量获取部门的下级部门
     */
    @Override
    public Map<String, List<Dept>> batchQueryChildDeptList(List<Long> deptIdList) {
        Map<String, List<Dept>> map = new HashMap<>();
        if (deptIdList.isEmpty()) {
            return map;
        }
        List<Dept> allDept = systemApi.getAllDept().getData();
        for (Long deptId : deptIdList) {
            List<Dept> deptList = DataUtil.selectChildrenByDept(deptId, allDept);
            map.put(deptId.toString(), deptList);
        }
        return map;
    }

    /**
     * 开始节点事件
     */
    @Override
    public void startNodeEvent(InstanceNodeRecordParamDto recordParamDto) {
        instanceNodeRecordService.startNodeEvent(recordParamDto);
    }

    /**
     * 流程创建了
     */
    @Override
    public void processStartEvent(InstanceRecordParamDto instanceRecordParamDto) {
        InstanceRecord entity = BeanUtil.copyProperties(instanceRecordParamDto, InstanceRecord.class);
        String flowId = instanceRecordParamDto.getFlowId();
        Workflow workflow = processService.getByFlowIdContainDeleted(flowId);
        String processInstanceId = instanceRecordParamDto.getProcessInstanceId();
        WorkflowGroup workflowGroup = groupService.getById(workflow.getGroupId());
        entity.setName(workflow.getFlowName());
        entity.setLogo(workflow.getIcon());
        entity.setUserId(instanceRecordParamDto.getUserId());
        entity.setFlowId(flowId);
        entity.setProcessInstanceId(processInstanceId);
        entity.setProcessInstanceBizKey(instanceRecordParamDto.getProcessInstanceBizKey());
        entity.setProcessInstanceBizCode(instanceRecordParamDto.getProcessInstanceBizCode());
        entity.setGroupId(workflowGroup.getId());
        entity.setGroupName(workflowGroup.getGroupName());
        entity.setStatus(InstanceRecordStatusEnum.ON_GOING.getCode());
        String processStr = workflow.getFlow();
        Node node = JsonUtil.parseObject(processStr, Node.class);
        if (node != null) {
            NodeUtil.addEndNode(node);
        }
        entity.setProcess(JsonUtil.toJSONString(node));
        instanceRecordService.save(entity);
    }

    /**
     * 完成节点事件
     */
    @Override
    public void endNodeEvent(InstanceNodeRecordParamDto recordParamDto) {
        //处理任务
        InstanceNodeRecord instanceNodeRecord = instanceNodeRecordService.lambdaQuery().eq(InstanceNodeRecord::getProcessInstanceId, recordParamDto.getProcessInstanceId()).eq(InstanceNodeRecord::getStatus, InstanceNodeRecordStatusEnum.ON_GOING.getCode()).eq(InstanceNodeRecord::getNodeId, recordParamDto.getNodeId()).eq(InstanceNodeRecord::getExecutionId, recordParamDto.getExecutionId()).one();
        if (instanceNodeRecord != null) {
            {
                //修改任务执行人员的状态
                processNodeRecordAssignUserService.lambdaUpdate().set(InstanceAssignUserRecord::getStatus, InstanceAssignUserRecordStatusEnum.PENDING.getCode()).set(InstanceAssignUserRecord::getTaskType, TaskTypeEnum.CANCEL.getValue()).eq(InstanceAssignUserRecord::getProcessInstanceId, recordParamDto.getProcessInstanceId()).eq(InstanceAssignUserRecord::getStatus, InstanceAssignUserRecordStatusEnum.ON_GOING.getCode()).eq(InstanceAssignUserRecord::getNodeId, recordParamDto.getNodeId()).eq(InstanceAssignUserRecord::getParentExecutionId, instanceNodeRecord.getExecutionId()).update(new InstanceAssignUserRecord());
            }
        }
        instanceNodeRecordService.endNodeEvent(recordParamDto);
    }

    /**
     * 节点取消
     */
    @Transactional
    @Override
    public void cancelNodeEvent(InstanceNodeRecordParamDto recordParamDto) {
        //处理任务
        List<InstanceNodeRecord> processInstanceNodeRecordList = instanceNodeRecordService.lambdaQuery().eq(InstanceNodeRecord::getProcessInstanceId, recordParamDto.getProcessInstanceId()).eq(InstanceNodeRecord::getStatus, InstanceNodeRecordStatusEnum.ON_GOING.getCode()).eq(InstanceNodeRecord::getNodeId, recordParamDto.getNodeId()).eq(InstanceNodeRecord::getExecutionId, recordParamDto.getExecutionId()).list();
        if (processInstanceNodeRecordList.size() > 1) {
            log.error("当前节点有多个进行中的，请查看:{}", JsonUtil.toJSONString(processInstanceNodeRecordList));
        }
        if (CollUtil.isNotEmpty(processInstanceNodeRecordList)) {
            Set<String> executionIdSet = processInstanceNodeRecordList.stream().map(InstanceNodeRecord::getExecutionId).collect(Collectors.toSet());
            //相关的用户任务置为已撤销
            processNodeRecordAssignUserService.lambdaUpdate().set(InstanceAssignUserRecord::getStatus, InstanceAssignUserRecordStatusEnum.PENDING.getCode()).set(InstanceAssignUserRecord::getTaskType, TaskTypeEnum.CANCEL.getValue()).eq(InstanceAssignUserRecord::getProcessInstanceId, recordParamDto.getProcessInstanceId()).eq(InstanceAssignUserRecord::getStatus, InstanceAssignUserRecordStatusEnum.ON_GOING.getCode()).eq(InstanceAssignUserRecord::getNodeId, recordParamDto.getNodeId()).in(InstanceAssignUserRecord::getParentExecutionId, executionIdSet).update(new InstanceAssignUserRecord());
        }
        instanceNodeRecordService.cancelNodeEvent(recordParamDto);
    }

    /**
     * 开始设置执行人
     */
    @Override
    public void createTaskEvent(InstanceAssignUserRecordParamDto processInstanceAssignUserRecordParamDto) {
        processNodeRecordAssignUserService.createTaskEvent(processInstanceAssignUserRecordParamDto);
    }

    /**
     * 任务结束事件
     */
    @Override
    public void taskCompletedEvent(InstanceAssignUserRecordParamDto processInstanceAssignUserRecordParamDto) {
        processNodeRecordAssignUserService.taskCompletedEvent(processInstanceAssignUserRecordParamDto);
    }

    /**
     * 任务结束
     */
    @Override
    public void taskEndEvent(InstanceAssignUserRecordParamDto processInstanceAssignUserRecordParamDto) {
        processNodeRecordAssignUserService.taskEndEvent(processInstanceAssignUserRecordParamDto);
    }


    /**
     * 实例结束
     */
    @Override
    public void processEndEvent(InstanceParamDto processInstanceParamDto) {
        processInstanceService.workflowEndEvent(processInstanceParamDto);
    }

    /**
     * 查询流程管理员
     */
    @Override
    public String queryProcessAdmin(String flowId) {
        Workflow workflow = processService.getByFlowId(flowId);
        return workflow.getAdminId();
    }

    /**
     * 查询流程数据
     */
    @Override
    public WorkflowDTO queryProcess(String flowId) {
        Workflow workflow = processService.getByFlowId(flowId);
        return BeanUtil.copyProperties(workflow, WorkflowDTO.class);
    }

    /**
     * 保存流程节点数据
     */
    @Override
    public void saveNodeData(NodeDataDto nodeDataDto) {
        nodeDataService.saveNodeData(nodeDataDto);
    }

    /***
     * 获取节点数据
     */
    @Override
    public String getNodeData(String flowId, String nodeId) {
        return nodeDataService.getNodeData(flowId, nodeId);
    }

    /**
     * 保存执行数据
     */
    @Override
    public void saveExecution(InstanceExecutionDto instanceExecutionDto) {
        InstanceExecution entity = BeanUtil.copyProperties(instanceExecutionDto, InstanceExecution.class);
        instanceExecutionService.save(entity);
    }
}
